package com.ficus.road.maintain.websocket;


import com.ficus.road.maintain.core.model.FrameDTO;
import com.ficus.road.maintain.core.utils.JsonUtils;
import com.ficus.road.maintain.service.DataProcessorManager;
import com.ficus.road.maintain.service.VideoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author xianwen.yang
 */
@Slf4j
public abstract class BaseWebSocketManager {

    /**
     * carId,List<Session>
     * 同一辆车可能存在多个session
     */
    public static final Map<String, List<Session>> sessions = new ConcurrentHashMap<>();

    public static DataProcessorManager dataProcessorManager;

    public static VideoService videoService;

    public BaseWebSocketManager() {
    }


    /**
     * 增加会话
     */
    public abstract void increaseSession(String carId, String sessionId);

    /**
     * 减少会话
     */
    public abstract void decreaseSession(String id, String sessionId);

    /**
     * 连接关闭
     *
     * @param session session
     */
    @OnClose
    public void onClose(Session session) {
        log.info("session close,sessionId={}", session.getId());
        synchronized (sessions) {
            sessions.forEach((k, v) -> {
                for (Session s : v) {
                    if (s.getId().equals(session.getId())) {
                        v.remove(s);
                        //承担关闭线程的任务
                        decreaseSession(k, session.getId());
                        break;
                    }
                }
            });
        }
    }

    /**
     * 服务端发生了错误
     *
     * @param session session
     * @param error   error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("onError", error);
    }


    /**
     * 收到客户端的消息
     *
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("receive message from web, message={}, sessionId={}", message, session.getId());
    }

    /**
     * 关闭ws
     *
     * @param uuid session的uuid
     */
    public void closeSession(String uuid) {
        List<Session> sessionsById = sessions.get(uuid);

        for (Session item : sessionsById) {
            synchronized (item) {
                try {
                    //将处理过的message通过webSocket的session传给前端
                    item.close();
                } catch (IOException e) {
                    log.error("close ws met Exception:", e);
                }
            }
        }
    }

    /**
     *  给发送的FrameDTO设置额外的属性值
     */
    protected void setExtensionAttr(FrameDTO frameDTO) {

    }

    /**
     * 向客戶端發送消息
     * <p>
     * 传进来的id可能是carId，也可能是uuid
     *
     * @param frameDTO
     * @param id
     */
    public boolean sentMessageById(FrameDTO frameDTO, String id) {
        List<Session> sessionsById = sessions.get(id);
        log.info("ws send Message By Id, id = {}, sessions = {}", id, sessionsById == null ? "null" : sessionsById.stream().map(Session::getId).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(sessionsById)) {
            return false;
        }
        setExtensionAttr(frameDTO);
        String message = JsonUtils.ObjectConvertorString(frameDTO);
        //疑问：一辆车可能建立多个session
        for (Session item : sessionsById) {
            synchronized (item) {
                try {
                    //将处理过的message通过webSocket的session传给前端
                    item.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("", e);
                }
            }
        }
//        log.info("ws message has been sent, sessionId = {}",id);
        return true;
    }


}